﻿// Sequencer.cs 
// Adapted from Charles Petzold
// http://www.charlespetzold.com/blog/2009/07/Simple-Electronic-Music-Sequencer-for-Silverlight.html

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Kindohm.KSynth.Library
{
    public class Sequencer : ISampleMaker, ISignalChainComponent
    {
        int tempo = 360;
        int samplesPerQuarter = 44100 / 6;
        int sampleCounter = 0;

        int accumulatedSeconds = 0;
        int accumulatedSampleTicks = 0;
        int positionIndex;

        public event SequencerPositionChangedEventHandler IndexChanged;

        public Oscillator Oscillator { get; set; }
        public ISampleMaker Input { get; set; }
        public ISampleMaker Output { get; set; }
        public IList<Pitch> Pitches { protected set; get; }

        public int Tempo
        {
            set
            {
                tempo = value;
                samplesPerQuarter = 44100 * 60 / tempo;
            }
            get
            {
                return tempo;
            }
        }

        public Sequencer()
        {
            Pitches = new List<Pitch>();
            positionIndex = -1;
        }

        public StereoSample GetSample()
        {
            sampleCounter++;

            if (sampleCounter > samplesPerQuarter)
            {
                positionIndex++;

                if (positionIndex >= Pitches.Count)
                    positionIndex = 0;

                if (IndexChanged != null)
                    IndexChanged(this, new SequencerPositionChangedEventArgs(positionIndex, 
                                                TimeSpan.FromSeconds(accumulatedSeconds + accumulatedSampleTicks / 44100.0)));

                Oscillator.Frequency = Pitches[positionIndex].Frequency;
                Oscillator.Envelope.Reset();
                Oscillator.FrequencyModulator.Envelope.Reset();
                Oscillator.AmplitudeModulator.Envelope.Reset();
                sampleCounter = 0;
            }

            // Bump up the counters for how much time has elapsed
            if (++accumulatedSampleTicks == 44100)
            {
                accumulatedSeconds++;
                accumulatedSampleTicks = 0;
            }

            return Oscillator.GetSample();
        }
    }
}
